use super::*;
use crate::Result;
use semver::Version;

/// Configuration migration trait
pub trait ConfigMigration: Send + Sync {
    /// Get the source version this migration applies to
    fn from_version(&self) -> &str;
    
    /// Get the target version this migration produces
    fn to_version(&self) -> &str;
    
    /// Apply the migration to the configuration
    fn migrate(&self, config: &mut serde_json::Value) -> Result<()>;
    
    /// Get a description of what this migration does
    fn description(&self) -> &str;
}

/// Configuration migration manager
pub struct ConfigMigrationManager {
    migrations: Vec<Box<dyn ConfigMigration>>,
}

impl ConfigMigrationManager {
    /// Create a new migration manager
    pub fn new() -> Self {
        Self {
            migrations: Vec::new(),
        }
    }
    
    /// Add a migration to the manager
    pub fn add_migration(&mut self, migration: Box<dyn ConfigMigration>) {
        self.migrations.push(migration);
    }
    
    /// Get the current configuration version
    pub fn current_version() -> &'static str {
        "1.0.0"
    }
    
    /// Check if a configuration needs migration
    pub fn needs_migration(&self, config: &serde_json::Value) -> Result<bool> {
        let config_version = self.get_config_version(config)?;
        let current_version = Version::parse(Self::current_version())?;
        let config_version_parsed = Version::parse(&config_version)?;
        
        Ok(config_version_parsed < current_version)
    }
    
    /// Migrate configuration to the current version
    pub fn migrate_config(&self, config: &mut serde_json::Value) -> Result<MigrationResult> {
        let original_version = self.get_config_version(config)?;
        let mut current_version = original_version.clone();
        let mut applied_migrations = Vec::new();
        
        // Sort migrations by version order
        let mut sorted_migrations = self.migrations.iter().collect::<Vec<_>>();
        sorted_migrations.sort_by(|a, b| {
            let version_a = Version::parse(a.from_version()).unwrap_or_else(|_| Version::new(0, 0, 0));
            let version_b = Version::parse(b.from_version()).unwrap_or_else(|_| Version::new(0, 0, 0));
            version_a.cmp(&version_b)
        });
        
        // Apply migrations in sequence
        for migration in sorted_migrations {
            if current_version == migration.from_version() {
                migration.migrate(config)?;
                current_version = migration.to_version().to_string();
                applied_migrations.push(MigrationInfo {
                    from_version: migration.from_version().to_string(),
                    to_version: migration.to_version().to_string(),
                    description: migration.description().to_string(),
                });
            }
        }
        
        // Update the version in the configuration
        self.set_config_version(config, &current_version)?;
        
        Ok(MigrationResult {
            original_version,
            final_version: current_version,
            applied_migrations,
        })
    }
    
    /// Get the version from a configuration object
    fn get_config_version(&self, config: &serde_json::Value) -> Result<String> {
        config
            .get("version")
            .and_then(|v| v.as_str())
            .map(|s| s.to_string())
            .ok_or_else(|| ConfigError::InvalidFormat("Missing version field".to_string()).into())
    }
    
    /// Set the version in a configuration object
    fn set_config_version(&self, config: &mut serde_json::Value, version: &str) -> Result<()> {
        if let serde_json::Value::Object(map) = config {
            map.insert("version".to_string(), serde_json::Value::String(version.to_string()));
            Ok(())
        } else {
            Err(ConfigError::InvalidFormat("Configuration is not an object".to_string()).into())
        }
    }
}

impl Default for ConfigMigrationManager {
    fn default() -> Self {
        let mut manager = Self::new();

        // Add built-in migrations in chronological order
        manager.add_migration(Box::new(Migration0_1_0To0_2_0));
        manager.add_migration(Box::new(Migration0_2_0To1_0_0));

        manager
    }
}

/// Migration result information
#[derive(Debug, Clone)]
pub struct MigrationResult {
    pub original_version: String,
    pub final_version: String,
    pub applied_migrations: Vec<MigrationInfo>,
}

/// Information about an applied migration
#[derive(Debug, Clone)]
pub struct MigrationInfo {
    pub from_version: String,
    pub to_version: String,
    pub description: String,
}

/// Migration from version 0.1.0 to 0.2.0
struct Migration0_1_0To0_2_0;

impl ConfigMigration for Migration0_1_0To0_2_0 {
    fn from_version(&self) -> &str {
        "0.1.0"
    }

    fn to_version(&self) -> &str {
        "0.2.0"
    }

    fn migrate(&self, config: &mut serde_json::Value) -> Result<()> {
        if let serde_json::Value::Object(map) = config {
            // Migrate editor settings: rename camelCase to snake_case
            if let Some(editor) = map.get_mut("editor") {
                if let serde_json::Value::Object(editor_map) = editor {
                    // Rename fontSize to font_size
                    if let Some(font_size) = editor_map.remove("fontSize") {
                        editor_map.insert("font_size".to_string(), font_size);
                    }

                    // Rename tabSize to tab_size
                    if let Some(tab_size) = editor_map.remove("tabSize") {
                        editor_map.insert("tab_size".to_string(), tab_size);
                    }

                    // Rename lineHeight to line_height
                    if let Some(line_height) = editor_map.remove("lineHeight") {
                        editor_map.insert("line_height".to_string(), line_height);
                    }
                }
            }

            // Migrate appearance settings
            if let Some(appearance) = map.get_mut("appearance") {
                if let serde_json::Value::Object(appearance_map) = appearance {
                    // Rename uiFontSize to ui_font_size
                    if let Some(ui_font_size) = appearance_map.remove("uiFontSize") {
                        appearance_map.insert("ui_font_size".to_string(), ui_font_size);
                    }
                }
            }
        }

        Ok(())
    }

    fn description(&self) -> &str {
        "Migrate from version 0.1.0 to 0.2.0: rename camelCase fields to snake_case"
    }
}

/// Migration from version 0.2.0 to 1.0.0
struct Migration0_2_0To1_0_0;

impl ConfigMigration for Migration0_2_0To1_0_0 {
    fn from_version(&self) -> &str {
        "0.2.0"
    }

    fn to_version(&self) -> &str {
        "1.0.0"
    }
    
    fn migrate(&self, config: &mut serde_json::Value) -> Result<()> {
        if let serde_json::Value::Object(map) = config {
            // Add new sections that didn't exist in 0.2.0
            if !map.contains_key("performance") {
                map.insert("performance".to_string(), serde_json::json!({
                    "max_memory_mb": 1024,
                    "monitoring": false,
                    "worker_threads": 0,
                    "cache_size_mb": 256,
                    "lazy_loading": true,
                    "debounce_delay": 300
                }));
            }

            if !map.contains_key("advanced") {
                map.insert("advanced".to_string(), serde_json::json!({
                    "debug_mode": false,
                    "log_level": "Info",
                    "experimental_features": false,
                    "telemetry": {
                        "enabled": false,
                        "crash_reports": false,
                        "usage_stats": false
                    },
                    "developer": {
                        "tools_enabled": false,
                        "show_metrics": false,
                        "hot_reload": false
                    }
                }));
            }

            // Migrate appearance settings
            if let Some(appearance) = map.get_mut("appearance") {
                if let serde_json::Value::Object(appearance_map) = appearance {
                    // Convert old theme values to new enum format
                    if let Some(theme) = appearance_map.get_mut("theme") {
                        if let Some(theme_str) = theme.as_str() {
                            let new_theme = match theme_str {
                                "light" => "Light",
                                "dark" => "Dark",
                                _ => "Auto",
                            };
                            *theme = serde_json::Value::String(new_theme.to_string());
                        }
                    }

                    // Add new appearance fields
                    if !appearance_map.contains_key("window_transparency") {
                        appearance_map.insert("window_transparency".to_string(),
                                            serde_json::Value::Number(serde_json::Number::from_f64(1.0).unwrap()));
                    }

                    if !appearance_map.contains_key("animations") {
                        appearance_map.insert("animations".to_string(),
                                            serde_json::Value::Bool(true));
                    }
                }
            }

            // Add editor enhancements
            if let Some(editor) = map.get_mut("editor") {
                if let serde_json::Value::Object(editor_map) = editor {
                    // Add new editor fields
                    if !editor_map.contains_key("cursor_style") {
                        editor_map.insert("cursor_style".to_string(),
                                        serde_json::Value::String("Line".to_string()));
                    }

                    if !editor_map.contains_key("cursor_blink_rate") {
                        editor_map.insert("cursor_blink_rate".to_string(),
                                        serde_json::Value::Number(500.into()));
                    }
                }
            }

            // Add extensions section
            if !map.contains_key("extensions") {
                map.insert("extensions".to_string(), serde_json::json!({
                    "enabled": true,
                    "auto_update": true,
                    "extension_dirs": [],
                    "disabled_extensions": []
                }));
            }
        }

        Ok(())
    }

    fn description(&self) -> &str {
        "Migrate from version 0.2.0 to 1.0.0: add new configuration sections and enhance existing ones"
    }
}

/// Configuration version checker
pub struct ConfigVersionChecker;

impl ConfigVersionChecker {
    /// Check if a configuration version is supported
    pub fn is_supported_version(version: &str) -> bool {
        match Version::parse(version) {
            Ok(v) => {
                let min_version = Version::parse("0.1.0").unwrap();
                let max_version = Version::parse(ConfigMigrationManager::current_version()).unwrap();
                v >= min_version && v <= max_version
            }
            Err(_) => false,
        }
    }
    
    /// Get the minimum supported version
    pub fn min_supported_version() -> &'static str {
        "0.1.0"
    }
    
    /// Get the maximum supported version
    pub fn max_supported_version() -> &'static str {
        ConfigMigrationManager::current_version()
    }
    
    /// Check if a version is newer than the current version
    pub fn is_newer_version(version: &str) -> Result<bool> {
        let version_parsed = Version::parse(version)?;
        let current_version = Version::parse(ConfigMigrationManager::current_version())?;
        Ok(version_parsed > current_version)
    }
    
    /// Check if a version is older than the minimum supported version
    pub fn is_too_old(version: &str) -> Result<bool> {
        let version_parsed = Version::parse(version)?;
        let min_version = Version::parse(Self::min_supported_version())?;
        Ok(version_parsed < min_version)
    }
}

/// Configuration compatibility checker
pub struct ConfigCompatibilityChecker;

impl ConfigCompatibilityChecker {
    /// Check if a configuration is compatible with the current version
    pub fn check_compatibility(config: &serde_json::Value) -> CompatibilityResult {
        let mut result = CompatibilityResult {
            is_compatible: true,
            issues: Vec::new(),
            warnings: Vec::new(),
        };
        
        // Check version
        if let Some(version) = config.get("version").and_then(|v| v.as_str()) {
            if !ConfigVersionChecker::is_supported_version(version) {
                result.is_compatible = false;
                result.issues.push(format!("Unsupported configuration version: {}", version));
            }
            
            if ConfigVersionChecker::is_too_old(version).unwrap_or(false) {
                result.warnings.push(format!("Configuration version {} is very old and may not support all features", version));
            }
        } else {
            result.is_compatible = false;
            result.issues.push("Missing version field in configuration".to_string());
        }
        
        // Check required fields
        let required_sections = ["editor", "appearance", "files"];
        for section in &required_sections {
            if !config.get(section).is_some() {
                result.warnings.push(format!("Missing configuration section: {}", section));
            }
        }
        
        result
    }
}

/// Compatibility check result
#[derive(Debug, Clone)]
pub struct CompatibilityResult {
    pub is_compatible: bool,
    pub issues: Vec<String>,
    pub warnings: Vec<String>,
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_migration_manager() {
        let manager = ConfigMigrationManager::default();
        
        // Test configuration that needs migration
        let mut config = serde_json::json!({
            "version": "0.1.0",
            "editor": {
                "fontSize": 14,
                "tabSize": 4
            },
            "appearance": {
                "theme": "dark"
            }
        });
        
        assert!(manager.needs_migration(&config).unwrap());
        
        let result = manager.migrate_config(&mut config).unwrap();
        assert_eq!(result.original_version, "0.1.0");
        assert_eq!(result.final_version, "1.0.0");
        assert_eq!(result.applied_migrations.len(), 2);
        
        // Check that fields were migrated correctly
        assert_eq!(config["editor"]["font_size"], 14);
        assert_eq!(config["editor"]["tab_size"], 4);
        assert_eq!(config["appearance"]["theme"], "Dark");
        assert!(config["performance"].is_object());
        assert!(config["advanced"].is_object());
    }
    
    #[test]
    fn test_version_checker() {
        assert!(ConfigVersionChecker::is_supported_version("1.0.0"));
        assert!(ConfigVersionChecker::is_supported_version("0.1.0"));
        assert!(!ConfigVersionChecker::is_supported_version("2.0.0"));
        assert!(!ConfigVersionChecker::is_supported_version("0.0.1"));
    }
    
    #[test]
    fn test_compatibility_checker() {
        let config = serde_json::json!({
            "version": "1.0.0",
            "editor": {},
            "appearance": {},
            "files": {}
        });
        
        let result = ConfigCompatibilityChecker::check_compatibility(&config);
        assert!(result.is_compatible);
        assert!(result.issues.is_empty());
    }
}
